package CTCOffice;


import java.io.PrintWriter;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.processing.Processor;

/**
 * SelfEncrypter is a class designed to authenticate a user using the n + 1 encryption algorithm.
 * Once the object is created, one can request the validation of the credentials which were provided.
 * A boolean result will be generated which can be used to determine if the user should or should not
 * gain access to the system.
 * 
 * @author Mike Hearing
 */
public class SelfEncrypter { 
	private String sUsername, sPassword, sFilePointer;

	/**
	 * Creates a SelfEncrypter object based on the specified parameters, which can be referenced using the 
	 * validate method to verify the credentials.
	 * 
	 * @param uname Username of the individual to be authenticated.
	 * @param pword Password to be checked for the specified username.
	 * @param fp The name of the file which should be checked for the credentials.
	 */
	public SelfEncrypter(String uname, String pword, String fp) {
		sUsername = uname;
		sPassword = pword;
		sFilePointer = fp;
	}

	/**
	 * Returns and encrypted version of the password specified by the user in order to compare against the
	 * encrypted one on file. This method employs the n + 1 encryption algorithm which is used to encrypt
	 * a password against itself.
	 * 
	 * @return A String containing the encrypted user password
	 * @see String
	 */
	private String generateEncryption() {
		char[] cPassword = sPassword.toCharArray();

		if(cPassword.length != 0)
			for(int i = 0; i < sPassword.length(); i++)
				cPassword[i] += cPassword[(i+1) % sPassword.length()];

		return new String(cPassword);
	}

	/**
	 * Creates a new user in the specified file based on the credentials provided to the SelfEncrypter constructor.
	 */
	public void createUser() {
		try {
			PrintWriter writer = new PrintWriter(Processor.class.getResourceAsStream(this.sFilePointer).toString(), "UTF-8");
	        writer.println(sUsername + "|" + generateEncryption() + "|");
	        writer.close(); 
		} catch(Exception ex) { System.out.println("Failed"); }
	}

	/**
	 * Returns the specified users data from the storage file. This is done using regex and an internal formatter in order
	 * to ensure that the file was generated to specification and not an imitation.
	 * 
	 * @return A String containing the users encrypted password
	 */
	private String retrieveUser() {
		try {
			Scanner sFile = new Scanner(Processor.class.getResourceAsStream(sFilePointer), "UTF-8");
			while(sFile.hasNextLine()) {
				String sLine = sFile.next();
	
				//sUsername|sEcryptedPassword|
				Pattern pExpression = Pattern.compile("^" + sUsername + "\\|([^|]+)\\|");
				Matcher mSubject = pExpression.matcher(sLine);
	
				//Single use, no while iterations
				if(mSubject.find()) {
					sFile.close();
					return mSubject.group(1);
				}
			}
			
			sFile.close();
		} catch(Exception ex) { }

		return "FAILURETOAUTHENTICATE";
	}

	/**
	 * Validates the account based on the credential provided to the SelfEncrypter constructor.
	 * The password is first encrypted and then compared against the one on file. If there is a 
	 * match then the method will return a Boolean indicating such.
	 * 
	 * @return A Boolean representing the successfulness of the authentication for a given user.
	 */
	public Boolean validate() {
		return (retrieveUser().equals(generateEncryption()));
	}
}